﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using M3G;
using System.Drawing;

/**
 * メモ: ImageBaseではメモリをアロケートしないが、
 * Image2Dクラスのコンストラクターで１枚画像をAllocateするので
 * ここで明示的にAllocateする必要はない
 * */

namespace MyTestProject {
    public class TestImageBase {

        /**
         * コンストラクターのテスト1
         * 空の画像
         * */
        [Fact]
        public void TestConstructor1 () {
            var img = (ImageBase)new Image2D (ImageBase.RGBA, 64, 64);

            Assert.Equal (ImageBase.RGBA, img.Format);
            Assert.Equal (64, img.Width);
            Assert.Equal (64, img.Height);
            Assert.Equal (true, img.Mutable);
            Assert.Equal (true, img.Mipmapped);
            Assert.Equal (true, img.MipmapGenerateEnabled);
        }

        /**
         * オプション全部入りのコンストラクターのテスト
         * */
        [Fact]
        public void TestConstructor2 () {
            var option = ImageBase.LossLess | ImageBase.NoMipmap | ImageBase.YUp;
            var img = (ImageBase)new Image2D (ImageBase.RGBA | option, 64, 64);

            Assert.Equal (ImageBase.RGBA, img.Format);
            Assert.Equal (64, img.Width);
            Assert.Equal (64, img.Height);
            Assert.Equal (true, img.Mutable);
            Assert.Equal (false, img.Mipmapped);
            Assert.Equal (true, img.MipmapGenerateEnabled);
        }

        [Fact]
        public void TestSetMipmapGenerateEnable () {
            var img = (ImageBase)new Image2D (ImageBase.RGBA, 64, 64);

            img.MipmapGenerateEnabled = false;
            Assert.Equal (true, img.Mipmapped);
            Assert.Equal (false, img.MipmapGenerateEnabled);
        }

        [Fact]
        public void TestComit () {
            var img = (ImageBase)new Image2D (ImageBase.RGBA, 64, 64);
            img.Commit ();

            Assert.Equal (false, img.Mutable);
        }

        /**
         * PNG画像の保存のテスト1
         * オプションなしで作成した画像のセーブ
         * */
        [Fact]
        public void TestSave1 () {
            var img1 = (ImageBase)new Image2D (ImageBase.Alpha, 64, 64);
            var img2 = (ImageBase)new Image2D (ImageBase.Luminance, 64, 64);
            var img3 = (ImageBase)new Image2D (ImageBase.LuminanceAlpha, 64, 64);
            var img4 = (ImageBase)new Image2D (ImageBase.RGB, 64, 64);
            var img5 = (ImageBase)new Image2D (ImageBase.RGBA, 64, 64);
            var img6 = (ImageBase)new Image2D (ImageBase.RGB565, 64, 64);
            var img7 = (ImageBase)new Image2D (ImageBase.RGBA5551, 64, 64);
            var img8 = (ImageBase)new Image2D (ImageBase.RGBA4444, 64, 64);

            img1.Save (0, 0, "TestImageBase-Save1-Alpha.png");
            img2.Save (0, 0, "TestImageBase-Save1-Luminance.png");
            img3.Save (0, 0, "TestImageBase-Save1-LuminanceAlpha.png");
            img4.Save (0, 0, "TestImageBase-Save1-RGB.png");
            img5.Save (0, 0, "TestImageBase-Save1-RGBA.png");
            img6.Save (0, 0, "TestImageBase-Save1-RGB565.png");
            img7.Save (0, 0, "TestImageBase-Save1-RGBA5551.png");
            img8.Save (0, 0, "TestImageBase-Save1-RGBA4444.png");
        }

        /**
         * PNG画像の保存のテスト2
         * オプション全部入りで作成した画像のセーブ
         * */
        [Fact]
        public void TestSave2 () {
            var option = ImageBase.LossLess | ImageBase.NoMipmap | ImageBase.YUp;
            var img1 = (ImageBase)new Image2D (ImageBase.Alpha | option, 64, 64);
            var img2 = (ImageBase)new Image2D (ImageBase.Luminance | option, 64, 64);
            var img3 = (ImageBase)new Image2D (ImageBase.LuminanceAlpha | option, 64, 64);
            var img4 = (ImageBase)new Image2D (ImageBase.RGB | option, 64, 64);
            var img5 = (ImageBase)new Image2D (ImageBase.RGBA | option, 64, 64);
            var img6 = (ImageBase)new Image2D (ImageBase.RGB565 | option, 64, 64);
            var img7 = (ImageBase)new Image2D (ImageBase.RGBA5551 | option, 64, 64);
            var img8 = (ImageBase)new Image2D (ImageBase.RGBA4444 | option, 64, 64);

            img1.Save (0, 0, "TestImageBase-Save2-Alpha.png");
            img2.Save (0, 0, "TestImageBase-Save2-Luminance.png");
            img3.Save (0, 0, "TestImageBase-Save2-LuminanceAlpha.png");
            img4.Save (0, 0, "TestImageBase-Save2-RGB.png");
            img5.Save (0, 0, "TestImageBase-Save2-RGBA.png");
            img6.Save (0, 0, "TestImageBase-Save2-RGB565.png");
            img7.Save (0, 0, "TestImageBase-Save2-RGBA5551.png");
            img8.Save (0, 0, "TestImageBase-Save2-RGBA4444.png");
        }

        /**
         * PNG画像の保存のテスト3
         * ミップマップ階層全体を1つのPNG画像として出力するセーブのテスト
         * */
        [Fact]
        public void TestSave3 () {
            var img = (ImageBase)new Image2D (ImageBase.RGB, 64, 64);
            img.GenerateMipmap (0);

            img.SaveMipmapPyramid (0, "TestImageBase-Save3.png");
        }


        [Fact]
        public void TestMaxMipLevel () {
            var img1 = (ImageBase)new Image2D (ImageBase.RGB, 1, 1);
            var img2 = (ImageBase)new Image2D (ImageBase.RGB, 16, 16);
            var img3 = (ImageBase)new Image2D (ImageBase.RGB, 16, 64);

            Assert.Equal (0, img1.MaxMipLevel);
            Assert.Equal (4, img2.MaxMipLevel);
            Assert.Equal (6, img3.MaxMipLevel);
        }

        [Fact]
        public void TestMiplevelWidth () {
            var img = (ImageBase)new Image2D (ImageBase.RGB, 16, 64);

            Assert.Equal (16, img.MiplevelWidth (0));
            Assert.Equal (8, img.MiplevelWidth (1));
            Assert.Equal (4, img.MiplevelWidth (2));
            Assert.Equal (2, img.MiplevelWidth (3));
            Assert.Equal (1, img.MiplevelWidth (4));
            Assert.Equal (1, img.MiplevelWidth (5));
            Assert.Equal (1, img.MiplevelWidth (6));
        }

        [Fact]
        public void TestMiplevelHeight () {
            var img = (ImageBase)new Image2D (ImageBase.RGB, 64, 16);

            Assert.Equal (16, img.MiplevelHeight (0));
            Assert.Equal (8, img.MiplevelHeight (1));
            Assert.Equal (4, img.MiplevelHeight (2));
            Assert.Equal (2, img.MiplevelHeight (3));
            Assert.Equal (1, img.MiplevelHeight (4));
            Assert.Equal (1, img.MiplevelHeight (5));
            Assert.Equal (1, img.MiplevelHeight (6));
        }

        [Fact]
        public void TestFormatToBpp () {
            Assert.Equal (1, ImageBase.FormatToBpp (ImageBase.Alpha));
            Assert.Equal (1, ImageBase.FormatToBpp (ImageBase.Luminance));
            Assert.Equal (2, ImageBase.FormatToBpp (ImageBase.LuminanceAlpha));
            Assert.Equal (3, ImageBase.FormatToBpp (ImageBase.RGB));
            Assert.Equal (4, ImageBase.FormatToBpp (ImageBase.RGBA));
            Assert.Equal (3, ImageBase.FormatToBpp (ImageBase.RGB565));
            Assert.Equal (4, ImageBase.FormatToBpp (ImageBase.RGBA5551));
            Assert.Equal (4, ImageBase.FormatToBpp (ImageBase.RGBA4444));
        }

        /**
         * ピクセルの書き込みのテスト1
         * 画面全体を変更
         * */
        [Fact]
        public void TestSetPixels1 () {
            var img    = (ImageBase)new Image2D (ImageBase.RGB | ImageBase.NoMipmap, 64, 64);
            var pixels = new byte[64 * 64 * 3];
            for (var y=0; y < 64; y++) {
                for (var x=0; x < 64; x++) {
                    pixels[(y * 64 + x) * 3 + 0] = (byte)(x / 32 * 255);
                    pixels[(y * 64 + x) * 3 + 1] = (byte)(y / 32 * 255);
                    pixels[(y * 64 + x) * 3 + 2] = 0;
                }
            }

            img.SetPixels (0, 0, pixels);
            img.Save (0, 0, "TestImageBase-SetPixels1.png");
        }

        /**
         * ピクセルの書き込みのテスト1
         * 画面の一部を変更
         * */
        [Fact]
        public void TestSetPixels2 () {
            var img    = (ImageBase)new Image2D (ImageBase.RGB | ImageBase.NoMipmap, 64, 64);
            var pixels = new byte[32 * 32 * 3];
            for (var y=0; y < 32; y++) {
                for (var x=0; x < 32; x++) {
                    pixels[(y * 32 + x) * 3 + 0] = (byte)(x / 16 * 255);
                    pixels[(y * 32 + x) * 3 + 1] = (byte)(y / 16 * 255);
                    pixels[(y * 32 + x) * 3 + 2] = 0;
                }
            }

            img.SetPixels (0, 0, 16, 16, 32, 32, pixels);
            img.Save (0, 0, "TestImageBase-SetPixels2.png");
        }

        /**
         * ミップマップの自動生成のテスト
         * */
        [Fact]
        public void TestGenerateMipmap () {
            var img = (ImageBase)new Image2D (ImageBase.RGB, 64, 64);
            var pixels = new byte[64 * 64 * 3];
            for (var y=0; y < 64; y++) {
                for (var x=0; x < 64; x++) {
                    pixels[(y * 64 + x) * 3 + 0] = (byte)(x / 32 * 255);
                    pixels[(y * 64 + x) * 3 + 1] = (byte)(y / 32 * 255);
                    pixels[(y * 64 + x) * 3 + 2] = 0;
                }
            }

            img.SetPixels (0, 0, pixels);
            img.GenerateMipmap (0);

            for (var m=0; m <= img.MaxMipLevel; m++) {
                img.Save (0, m, "TestImageBase-GenerateMipmap-"+m+".png");
            }
        }


        /**
         * ピクセル変換のテスト1
         * Bitmap --> byte[]
         * */
        [Fact]
        public void TestConvertToPixels1 () {
            var bitmap = new Bitmap ("DragonYear.png");
            var pixels = ImageBase.ConvertToPixels (ImageBase.Luminance, bitmap);
            var img = (ImageBase)new Image2D (ImageBase.Luminance, bitmap.Width, bitmap.Height, pixels);

            img.Save (0, 0, "TestImageBase-ConvertToPixels1.png");
        }

        /**
         * ピクセル変換のテスト2
         * uint[] --> byte[]
         * */
        [Fact]
        public void TestConvertToPixels2 () {
            var bitmap     = new Bitmap ("DragonYear.png");
            var uintPixels = new uint[bitmap.Width * bitmap.Height];
            for (var y=0; y < bitmap.Height; y++) {
                for (var x=0; x < bitmap.Width; x++) {
                    var c = bitmap.GetPixel(x, y);
                    uintPixels[(y*bitmap.Width + x)] = (uint)(c.A << 24 | c.R << 16 | c.G << 8 | c.B << 0);
                }
            }
            var pixels = ImageBase.ConvertToPixels (ImageBase.RGBA, uintPixels);
            var img    = (ImageBase)new Image2D (ImageBase.RGBA, bitmap.Width, bitmap.Height, pixels);

            img.Save (0, 0, "TestImageBase-ConvertToPixels2.png");
        }

        /**
         * ピクセル変換のテスト3
         * ushort[] --> byte[]
         * */
        [Fact]
        public void TestConvertToPixels3 () {
            var bitmap       = new Bitmap ("DragonYear.png");
            var ushortPixels = new ushort[bitmap.Width * bitmap.Height];
            for (var y=0; y < bitmap.Height; y++) {
                for (var x=0; x < bitmap.Width; x++) {
                    var r = (int)(bitmap.GetPixel (x, y).R / 255.0f * 31.0f);
                    var g = (int)(bitmap.GetPixel (x, y).G / 255.0f * 63.0f);
                    var b = (int)(bitmap.GetPixel (x, y).B / 255.0f * 31.0f);
                    ushortPixels[y * bitmap.Width + x] = (ushort)(r << 11 | g << 5 | b << 0);
                }
            }
            var pixels = ImageBase.ConvertToPixels (ImageBase.RGB565, ushortPixels);
            var img = (ImageBase)new Image2D (ImageBase.RGB565, bitmap.Width, bitmap.Height, pixels);

            img.Save (0, 0, "TestImageBase-ConvertToPixels3.png");
        }
    }
}
